package com.gph.saviorframework.mq.api.impl.rocketmq;

import com.alibaba.rocketmq.client.consumer.DefaultMQPushConsumer;
import com.alibaba.rocketmq.client.consumer.listener.ConsumeOrderlyContext;
import com.alibaba.rocketmq.client.consumer.listener.ConsumeOrderlyStatus;
import com.alibaba.rocketmq.client.consumer.listener.MessageListenerOrderly;
import com.alibaba.rocketmq.client.exception.MQClientException;
import com.alibaba.rocketmq.common.UtilAll;
import com.alibaba.rocketmq.common.message.MessageExt;
import com.gph.saviorframework.mq.api.Message;
import com.gph.saviorframework.mq.api.PropertyKeyConst;
import com.gph.saviorframework.mq.api.impl.util.MQUtil;
import com.gph.saviorframework.mq.api.order.ConsumeOrderContext;
import com.gph.saviorframework.mq.api.order.MessageOrderListener;
import com.gph.saviorframework.mq.api.order.OrderAction;
import com.gph.saviorframework.mq.api.order.OrderConsumer;

import java.util.List;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;

public class OrderConsumerImpl extends MQClientAbstract implements OrderConsumer {

    private final DefaultMQPushConsumer defaultMQPushConsumer;

    private final ConcurrentHashMap<String/* Topic */, MessageOrderListener> subscribeTable =
            new ConcurrentHashMap<String, MessageOrderListener>();

    private final AtomicBoolean started = new AtomicBoolean(false);


    public OrderConsumerImpl(final Properties properties) {

        super(properties);
        this.defaultMQPushConsumer = new DefaultMQPushConsumer(new ClientRPCHook(sessionCredentials));

        String consumerGroup = properties.getProperty(PropertyKeyConst.ConsumerId);
        if (null == consumerGroup) {
            throw new com.gph.saviorframework.mq.api.exception.MQClientException("\'ConsumerId\' property is null");
        }

        String suspendTimeMillis = properties.getProperty(PropertyKeyConst.SuspendTimeMillis);
        if (!UtilAll.isBlank(suspendTimeMillis)) {
            try {
                this.defaultMQPushConsumer.setSuspendCurrentQueueTimeMillis(Long.parseLong(suspendTimeMillis));
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
        }

        String maxReconsumeTimes = properties.getProperty(PropertyKeyConst.MaxReconsumeTimes);
        if (!UtilAll.isBlank(maxReconsumeTimes)) {
            try {
                this.defaultMQPushConsumer.setMaxReconsumeTimes(Integer.parseInt(maxReconsumeTimes));
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
        }

        String consumeTimeout = properties.getProperty(PropertyKeyConst.ConsumeTimeout);
        if (!UtilAll.isBlank(consumeTimeout)) {
            try {
                this.defaultMQPushConsumer.setConsumeTimeout(Integer.parseInt(consumeTimeout));
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
        }

        boolean isVipChannelEnabled = Boolean.parseBoolean(properties.getProperty(PropertyKeyConst.isVipChannelEnabled, "false"));
        this.defaultMQPushConsumer.setVipChannelEnabled(isVipChannelEnabled);

        this.defaultMQPushConsumer.setConsumerGroup(consumerGroup);
        this.defaultMQPushConsumer.setInstanceName(this.buildIntanceName());
        this.defaultMQPushConsumer.setNamesrvAddr(this.getNameServerAddr());

        if (properties.containsKey(PropertyKeyConst.ConsumeThreadNums)) {
            this.defaultMQPushConsumer.setConsumeThreadMin(Integer.valueOf(properties.get(PropertyKeyConst.ConsumeThreadNums).toString()));

            this.defaultMQPushConsumer.setConsumeThreadMax(Integer.valueOf(properties.get(PropertyKeyConst.ConsumeThreadNums).toString()));
        }
    }

    public void start() {
        this.defaultMQPushConsumer.registerMessageListener(new MessageListenerOrderlyImpl());
        try {
            if (started.compareAndSet(false, true)) {
                this.defaultMQPushConsumer.start();
            }
        } catch (Exception e) {
            throw new com.gph.saviorframework.mq.api.exception.MQClientException(e);
        }
    }

    public void shutdown() {
        if (started.compareAndSet(true, false)) {
            this.defaultMQPushConsumer.shutdown();
        }
    }

    public void subscribe(String topic, String subExpression, MessageOrderListener listener) {
        if (null == topic) {
            throw new com.gph.saviorframework.mq.api.exception.MQClientException("topic is null");
        }

        if (null == listener) {
            throw new com.gph.saviorframework.mq.api.exception.MQClientException("listener is null");
        }

        try {
            this.subscribeTable.put(topic, listener);
            this.defaultMQPushConsumer.subscribe(topic, subExpression);
        } catch (MQClientException e) {
            throw new com.gph.saviorframework.mq.api.exception.MQClientException("defaultMQPushConsumer subscribe exception", e);
        }
    }

    class MessageListenerOrderlyImpl implements MessageListenerOrderly {

        public ConsumeOrderlyStatus consumeMessage(List<MessageExt> arg0, ConsumeOrderlyContext arg1) {
            MessageExt msgRMQ = arg0.get(0);
            Message msg = MQUtil.msgConvert(msgRMQ);
            msg.setMsgID(msgRMQ.getMsgId());

            MessageOrderListener listener = OrderConsumerImpl.this.subscribeTable.get(msg.getTopic());
            if (null == listener) {
                throw new com.gph.saviorframework.mq.api.exception.MQClientException("MessageOrderListener is null");
            }

            final ConsumeOrderContext context = new ConsumeOrderContext();
            OrderAction action = listener.consume(msg, context);
            if (action != null) {
                switch (action) {
                    case Success:
                        return ConsumeOrderlyStatus.SUCCESS;
                    case Suspend:
                        return ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT;
                    default:
                        break;
                }
            }

            return ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT;
        }
    }

    public boolean isStarted() {
        return started.get();
    }

    public boolean isClosed() {
        return !isStarted();
    }
}